package fr.norsys.mapper.console.utils;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import fr.norsys.mapper.console.service.PropertyServiceImpl;

public class BeanUtils {
	private final static Log log = LogFactory.getLog(PropertyServiceImpl.class);
	/**
	 * This method transforms a bean instance into a map from property names to
	 * property values. This method as all methods in this class never throws an
	 * exception. If an attribute's value cannot be retrieved for any reason, it
	 * is set to null in the return map.
	 * 
	 * @param o
	 *            an Object following the javabean pattern.
	 * @return a Map < String, Object > instance
	 */
	public static Map toMap(Object o) {
		Map ret = new HashMap();
		Class cls = o.getClass();
		BeanInfo info;
		try {
			info = Introspector.getBeanInfo(cls);
		} catch (IntrospectionException e) {
			return null;
		}
		PropertyDescriptor[] props = info.getPropertyDescriptors();
		Object[] a = new Object[0];
		for (int i = 0; i < props.length; i++) {
			/* try to write o */
			Method getter = props[i].getReadMethod();
			String name = props[i].getName();
			if (!"class".equals(name)) {
				try {
					Object val = getter.invoke(o, a);
					if(val != null)
						{ret.put(name, val);}
					/* if everything goes right, return */
				} catch (Exception e1) {
					log.error(e1);
				}
			}
		}
		return ret;
	}

	public static void toObject(Map map, Object obj) {
		BeanInfo info;
		try {
			info = Introspector.getBeanInfo(obj.getClass());
		} catch (IntrospectionException e) {
			return;
		}
		Object[] a = new Object[1];
		PropertyDescriptor[] props = info.getPropertyDescriptors();
		for (int i = 0; i < props.length; i++) {
			String name = props[i].getName();
			Object o = map.get(name);
			if (o != null) {
				a[0] = o;
				Method setter = props[i].getWriteMethod();
				try {
					setter.invoke(obj, a);
				} catch (Exception e) {
					log.error(e);
				}
			}
		}
	}

	public static void copyFilledProperties(Object end, Object begin) {
		BeanInfo beginInfo;
		BeanInfo endInfo;
		try {
			beginInfo = Introspector.getBeanInfo(begin.getClass());
			endInfo = Introspector.getBeanInfo(end.getClass());
		} catch (IntrospectionException e) {
			return;
		}
		PropertyDescriptor[] beginProps = beginInfo.getPropertyDescriptors();
		PropertyDescriptor[] endProps = endInfo.getPropertyDescriptors();
		for (int i = 0; i < beginProps.length; i++) {
			String name = beginProps[i].getName();
			if (!"class".equals(name)) {
				Method getter = beginProps[i].getReadMethod();
				Object value = null;
				try {
					value = getter.invoke(begin, new Object[0]);
				} catch (Exception e) {
					log.error(e);
				}
				if (value != null && name != null) {
					for (int j = 0; j < endProps.length; j++) {
						if (name.equals(endProps[j].getName())) {
							Method setter = endProps[j].getWriteMethod();
							try {
								setter.invoke(end, new Object[] { value });
							} catch (Exception e) {
								log.error(e);
							}
						}
					}
				}
			}
		}
	}
}